home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  37.4 KB  |  1,255 lines

  1. /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevx.c,v 1.7 2000/09/19 19:00:23 lpd Exp $ */
  20. /* X Windows driver for Ghostscript library */
  21. #include "gx.h"            /* for gx_bitmap; includes std.h */
  22. #include "math_.h"
  23. #include "memory_.h"
  24. #include "x_.h"
  25. #include "gserrors.h"
  26. #include "gsmatrix.h"        /* for gscoord.h */
  27. #include "gscoord.h"        /* for gs_currentmatrix */
  28. #include "gsdevice.h"        /* for gs_currentdevice */
  29. #include "gsparam.h"
  30. #include "gxdevice.h"
  31. #include "gxpath.h"
  32. #include "gxgetbit.h"
  33. #include "gxiparam.h"
  34. #include "gsiparm2.h"
  35. #include "gxdevmem.h"
  36. #include "gdevx.h"
  37.  
  38. /* Define whether to try to read back exposure events after XGetImage. */
  39. /****** THIS IS USELESS.  XGetImage DOES NOT GENERATE EXPOSURE EVENTS. ******/
  40. #define GET_IMAGE_EXPOSURES 0
  41.  
  42. /* GC descriptors */
  43. private_st_device_X();
  44.  
  45. /* Forward references */
  46. private int x_copy_image(P8(gx_device_X * xdev, const byte * base, int sourcex,
  47.                 int raster, int x, int y, int w, int h));
  48. private int set_tile(P2(gx_device *, const gx_strip_bitmap *));
  49. private void free_cp(P1(gx_device *));
  50.  
  51. /* Screen updating machinery */
  52. private void update_init(P1(gx_device_X *));
  53. private void update_do_flush(P1(gx_device_X *));
  54.  
  55. #define flush_text(xdev)\
  56.   if (IN_TEXT(xdev)) do_flush_text(xdev)
  57. private void do_flush_text(P1(gx_device_X *));
  58.  
  59. /* Driver procedures */
  60. /* (External procedures are declared in gdevx.h.) */
  61. /*extern int gdev_x_open(P1(gx_device_X *));*/
  62. private dev_proc_open_device(x_open);
  63. private dev_proc_get_initial_matrix(x_get_initial_matrix);
  64. private dev_proc_sync_output(x_sync);
  65. private dev_proc_output_page(x_output_page);
  66. /*extern int gdev_x_close(P1(gx_device_X *));*/
  67. private dev_proc_close_device(x_close);
  68. /*extern dev_proc_map_rgb_color(gdev_x_map_rgb_color);*/
  69. /*extern dev_proc_map_color_rgb(gdev_x_map_color_rgb);*/
  70. private dev_proc_fill_rectangle(x_fill_rectangle);
  71. private dev_proc_copy_mono(x_copy_mono);
  72. private dev_proc_copy_color(x_copy_color);
  73. /*extern dev_proc_get_params(gdev_x_get_params);*/
  74. /*extern dev_proc_put_params(gdev_x_put_params);*/
  75. /*extern dev_proc_get_xfont_procs(gdev_x_get_xfont_procs);*/
  76. private dev_proc_get_page_device(x_get_page_device);
  77. private dev_proc_strip_tile_rectangle(x_strip_tile_rectangle);
  78. private dev_proc_begin_typed_image(x_begin_typed_image);
  79. private dev_proc_get_bits_rectangle(x_get_bits_rectangle);
  80. /*extern dev_proc_get_xfont_procs(gdev_x_finish_copydevice);*/
  81.  
  82. /* The device descriptor */
  83. const gx_device_X gs_x11_device = {
  84.     std_device_color_stype_body(gx_device_X, 0, "x11", &st_device_X,
  85.               FAKE_RES * DEFAULT_WIDTH_10THS / 10,
  86.               FAKE_RES * DEFAULT_HEIGHT_10THS / 10,    /* x and y extent (nominal) */
  87.               FAKE_RES, FAKE_RES,    /* x and y density (nominal) */
  88.               /*dci_color( */ 24, 255, 256 /*) */ ),
  89.     {                /* std_procs */
  90.     x_open,
  91.     x_get_initial_matrix,
  92.     x_sync,
  93.     x_output_page,
  94.     x_close,
  95.     gdev_x_map_rgb_color,
  96.     gdev_x_map_color_rgb,
  97.     x_fill_rectangle,
  98.     NULL,            /* tile_rectangle */
  99.     x_copy_mono,
  100.     x_copy_color,
  101.     NULL,            /* draw_line */
  102.     NULL,            /* get_bits */
  103.     gdev_x_get_params,
  104.     gdev_x_put_params,
  105.     NULL,            /* map_cmyk_color */
  106.     gdev_x_get_xfont_procs,
  107.     NULL,            /* get_xfont_device */
  108.     NULL,            /* map_rgb_alpha_color */
  109.     x_get_page_device,
  110.     NULL,            /* get_alpha_bits */
  111.     NULL,            /* copy_alpha */
  112.     NULL,            /* get_band */
  113.     NULL,            /* copy_rop */
  114.     NULL,            /* fill_path */
  115.     NULL,            /* stroke_path */
  116.     NULL,            /* fill_mask */
  117.     NULL,            /* fill_trapezoid */
  118.     NULL,            /* fill_parallelogram */
  119.     NULL,            /* fill_triangle */
  120.     NULL,            /* draw_thin_line */
  121.     NULL,            /* begin_image */
  122.     NULL,            /* image_data */
  123.     NULL,            /* end_image */
  124.     x_strip_tile_rectangle,
  125.     NULL,            /* strip_copy_rop */
  126.     NULL,            /* get_clipping_box */
  127.     x_begin_typed_image,
  128.     x_get_bits_rectangle,
  129.     NULL,            /* map_color_rgb_alpha */
  130.     NULL,            /* create_compositor */
  131.     NULL,            /* get_hardware_params */
  132.     NULL,            /* text_begin */
  133.     gdev_x_finish_copydevice
  134.     },
  135.     gx_device_bbox_common_initial(0 /*false*/, 1 /*true*/, 1 /*true*/),
  136.     0 /*false*/,        /* is_buffered */
  137.     1 /*true*/,            /* IsPageDevice */
  138.     0,                /* MaxBitmap */
  139.     NULL,            /* buffer */
  140.     0,                /* buffer_size */
  141.     {                /* image */
  142.     0, 0,            /* width, height */
  143.     0, XYBitmap, NULL,    /* xoffset, format, data */
  144.     MSBFirst, 8,        /* byte-order, bitmap-unit */
  145.     MSBFirst, 8, 1,        /* bitmap-bit-order, bitmap-pad, depth */
  146.     0, 1,            /* bytes_per_line, bits_per_pixel */
  147.     0, 0, 0,        /* red_mask, green_mask, blue_mask */
  148.     NULL,            /* *obdata */
  149.     {NULL,            /* *(*create_image)() */
  150.      NULL,            /* (*destroy_image)() */
  151.      NULL,            /* (*get_pixel)() */
  152.      NULL,            /* (*put_pixel)() */
  153.      NULL,            /* *(*sub_image)() */
  154.      NULL            /* (*add_pixel)() */
  155.     },
  156.     },
  157.     NULL, NULL,            /* dpy, scr */
  158.                 /* (connection not initialized) */
  159.     NULL,            /* vinfo */
  160.     (Colormap) None,        /* cmap */
  161.     (Window) None,        /* win */
  162.     NULL,            /* gc */
  163.     (Window) None,        /* pwin */
  164.     (Pixmap) 0,            /* bpixmap */
  165.     0,                /* ghostview */
  166.     (Window) None,        /* mwin */
  167.     {identity_matrix_body},    /* initial matrix (filled in) */
  168.     (Atom) 0, (Atom) 0, (Atom) 0,    /* Atoms: NEXT, PAGE, DONE */
  169.     {                /* update */
  170.     {            /* box */
  171.         {max_int_in_fixed, max_int_in_fixed},
  172.         {min_int_in_fixed, min_int_in_fixed}
  173.     },
  174.     0,            /* area */
  175.     0,            /* total */
  176.     0            /* count */
  177.     },
  178.     (Pixmap) 0,            /* dest */
  179.     0L, (ulong)~0L,        /* colors_or, colors_and */
  180.     {                /* cp */
  181.     (Pixmap) 0,        /* pixmap */
  182.     NULL,            /* gc */
  183.     -1, -1            /* raster, height */
  184.     },
  185.     {                /* ht */
  186.     (Pixmap) None,        /* pixmap */
  187.     (Pixmap) None,        /* no_pixmap */
  188.     gx_no_bitmap_id,    /* id */
  189.     0, 0, 0,        /* width, height, raster */
  190.     0, 0            /* fore_c, back_c */
  191.     },
  192.     GXcopy,            /* function */
  193.     FillSolid,            /* fill_style */
  194.     0,                /* font */
  195.     0, 0,            /* back_color, fore_color */
  196.     0, 0,            /* background, foreground */
  197.     { 0 },            /* cman */
  198.     0, 0,            /* borderColor, borderWidth */
  199.     NULL,            /* geometry */
  200.     128, 5,            /* maxGrayRamp, maxRGBRamp */
  201.     NULL,            /* palette */
  202.     NULL, NULL, NULL,        /* regularFonts, symbolFonts, dingbatFonts */
  203.     NULL, NULL, NULL,        /* regular_fonts, symbol_fonts, dingbat_fonts */
  204.     1, 1,            /* useXFonts, useFontExtensions */
  205.     1, 0,            /* useScalableFonts, logXFonts */
  206.     0.0, 0.0,            /* xResolution, yResolution */
  207.     1,                /* useBackingPixmap */
  208.     1, 1,            /* useXPutImage, useXSetTile */
  209.  
  210.     0 /*false*/,        /* AlwaysUpdate */
  211.     20000,            /* MaxTempPixmap */
  212.     5000,            /* MaxTempImage */
  213.     100000,            /* MaxBufferedTotal */
  214.     100000,            /* MaxBufferedArea */
  215.     max_int,            /* MaxBufferedCount */
  216.  
  217.     {                /* text */
  218.     0,            /* item_count */
  219.     0,            /* char_count */
  220.     {0, 0},            /* origin */
  221.     0,            /* x */
  222.     {
  223.         {0}},        /* items */
  224.     {0}            /* chars */
  225.     }
  226. };
  227.  
  228. /* If XPutImage doesn't work, do it ourselves. */
  229. private int alt_put_image(P11(gx_device * dev, Display * dpy, Drawable win,
  230. GC gc, XImage * pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h));
  231.  
  232. #define put_image(dpy,win,gc,im,sx,sy,x,y,w,h)\
  233.   BEGIN\
  234.     if ( xdev->useXPutImage ) {\
  235.       if (XInitImage(im) == 0)\
  236.     return_error(gs_error_unknownerror);\
  237.       XPutImage(dpy,win,gc,im,sx,sy,x,y,w,h);\
  238.     } else {\
  239.       int code_ = alt_put_image(dev,dpy,win,gc,im,sx,sy,x,y,w,h);\
  240.       if ( code_ < 0 ) return code_;\
  241.     }\
  242.   END
  243.  
  244. /* Open the device.  Most of the code is in gdevxini.c. */
  245. private int
  246. x_open(gx_device * dev)
  247. {
  248.     gx_device_X *xdev = (gx_device_X *) dev;
  249.     int code = gdev_x_open(xdev);
  250.  
  251.     if (code < 0)
  252.     return code;
  253.     update_init(xdev);
  254.     return 0;
  255. }
  256.  
  257. /* Close the device. */
  258. private int
  259. x_close(gx_device * dev)
  260. {
  261.     gx_device_X *xdev = (gx_device_X *) dev;
  262.  
  263.     return gdev_x_close(xdev);
  264. }
  265.  
  266. /* Get initial matrix for X device. */
  267. /* This conflicts seriously with the code for page devices; */
  268. /* we only do it if Ghostview is active. */
  269. private void
  270. x_get_initial_matrix(gx_device * dev, gs_matrix * pmat)
  271. {
  272.     gx_device_X *xdev = (gx_device_X *) dev;
  273.  
  274.     if (!xdev->ghostview) {
  275.     gx_default_get_initial_matrix(dev, pmat);
  276.     return;
  277.     }
  278.     pmat->xx = xdev->initial_matrix.xx;
  279.     pmat->xy = xdev->initial_matrix.xy;
  280.     pmat->yx = xdev->initial_matrix.yx;
  281.     pmat->yy = xdev->initial_matrix.yy;
  282.     pmat->tx = xdev->initial_matrix.tx;
  283.     pmat->ty = xdev->initial_matrix.ty;
  284. }
  285.  
  286. /* Synchronize the display with the commands already given. */
  287. private int
  288. x_sync(gx_device * dev)
  289. {
  290.     gx_device_X *xdev = (gx_device_X *) dev;
  291.  
  292.     update_do_flush(xdev);
  293.     XSync(xdev->dpy, False);
  294.     return 0;
  295. }
  296.  
  297. /* Send event to ghostview process */
  298. void
  299. gdev_x_send_event(gx_device_X *xdev, Atom msg)
  300. {
  301.     XEvent event;
  302.  
  303.     event.xclient.type = ClientMessage;
  304.     event.xclient.display = xdev->dpy;
  305.     event.xclient.window = xdev->win;
  306.     event.xclient.message_type = msg;
  307.     event.xclient.format = 32;
  308.     event.xclient.data.l[0] = xdev->mwin;
  309.     event.xclient.data.l[1] = xdev->dest;
  310.     XSendEvent(xdev->dpy, xdev->win, False, 0, &event);
  311. }
  312.  
  313. /* Output "page" */
  314. private int
  315. x_output_page(gx_device * dev, int num_copies, int flush)
  316. {
  317.     gx_device_X *xdev = (gx_device_X *) dev;
  318.  
  319.     x_sync(dev);
  320.  
  321.     /* Send ghostview a "page" client event */
  322.     /* Wait for a "next" client event */
  323.     if (xdev->ghostview) {
  324.     XEvent event;
  325.  
  326.     gdev_x_send_event(xdev, xdev->PAGE);
  327.     XNextEvent(xdev->dpy, &event);
  328.     while (event.type != ClientMessage ||
  329.            event.xclient.message_type != xdev->NEXT) {
  330.         XNextEvent(xdev->dpy, &event);
  331.     }
  332.     }
  333.     return gx_finish_output_page(dev, num_copies, flush);
  334. }
  335.  
  336. /* Fill a rectangle with a color. */
  337. private int
  338. x_fill_rectangle(gx_device * dev,
  339.          int x, int y, int w, int h, gx_color_index color)
  340. {
  341.     gx_device_X *xdev = (gx_device_X *) dev;
  342.  
  343.     fit_fill(dev, x, y, w, h);
  344.     flush_text(xdev);
  345.     X_SET_FILL_STYLE(xdev, FillSolid);
  346.     X_SET_FORE_COLOR(xdev, color);
  347.     X_SET_FUNCTION(xdev, GXcopy);
  348.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  349.     /* If we are filling the entire screen, reset */
  350.     /* colors_or and colors_and.  It's wasteful to test this */
  351.     /* on every operation, but there's no separate driver routine */
  352.     /* for erasepage (yet). */
  353.     if (x == 0 && y == 0 && w == xdev->width && h == xdev->height) {
  354.     if (color == xdev->foreground || color == xdev->background)
  355.         gdev_x_free_dynamic_colors(xdev);
  356.     xdev->colors_or = xdev->colors_and = color;
  357.     }
  358.     if (xdev->bpixmap != (Pixmap) 0) {
  359.     x_update_add(xdev, x, y, w, h);
  360.     }
  361.     if_debug5('F', "[F] fill (%d,%d):(%d,%d) %ld\n",
  362.           x, y, w, h, (long)color);
  363.     return 0;
  364. }
  365.  
  366. /* Copy a monochrome bitmap. */
  367. private int
  368. x_copy_mono(gx_device * dev,
  369.         const byte * base, int sourcex, int raster, gx_bitmap_id id,
  370.         int x, int y, int w, int h,
  371.         gx_color_index zero, gx_color_index one)
  372. /*
  373.  * X doesn't directly support the simple operation of writing a color
  374.  * through a mask specified by an image.  The plot is the following:
  375.  *  If neither color is gx_no_color_index ("transparent"),
  376.  *      use XPutImage with the "copy" function as usual.
  377.  *  If the color either bitwise-includes or is bitwise-included-in
  378.  *      every color written to date
  379.  *      (a special optimization for writing black/white on color displays),
  380.  *      use XPutImage with an appropriate Boolean function.
  381.  *  Otherwise, do the following complicated stuff:
  382.  *      Create pixmap of depth 1 if necessary.
  383.  *      If foreground color is "transparent" then
  384.  *        invert the raster data.
  385.  *      Use XPutImage to copy the raster image to the newly
  386.  *        created Pixmap.
  387.  *      Install the Pixmap as the clip_mask in the X GC and
  388.  *        tweak the clip origin.
  389.  *      Do an XFillRectangle, fill style=solid, specifying a
  390.  *        rectangle the same size as the original raster data.
  391.  *      De-install the clip_mask.
  392.  */
  393. {
  394.     gx_device_X *xdev = (gx_device_X *) dev;
  395.     int function = GXcopy;
  396.  
  397.     x_pixel
  398.     bc = zero,
  399.     fc = one;
  400.  
  401.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  402.     flush_text(xdev);
  403.  
  404.     xdev->image.width = sourcex + w;
  405.     xdev->image.height = h;
  406.     xdev->image.data = (char *)base;
  407.     xdev->image.bytes_per_line = raster;
  408.     X_SET_FILL_STYLE(xdev, FillSolid);
  409.  
  410.     /* Check for null, easy 1-color, hard 1-color, and 2-color cases. */
  411.     if (zero != gx_no_color_index) {
  412.     if (one != gx_no_color_index) {
  413.         /* 2-color case. */
  414.         /* Simply replace existing bits with what's in the image. */
  415.     } else if (!(~xdev->colors_and & bc)) {
  416.         function = GXand;
  417.         fc = ~(x_pixel) 0;
  418.     } else if (!(~bc & xdev->colors_or)) {
  419.         function = GXor;
  420.         fc = 0;
  421.     } else {
  422.         goto hard;
  423.     }
  424.     } else {
  425.     if (one == gx_no_color_index) {        /* no-op */
  426.         return 0;
  427.     } else if (!(~xdev->colors_and & fc)) {
  428.         function = GXand;
  429.         bc = ~(x_pixel) 0;
  430.     } else if (!(~fc & xdev->colors_or)) {
  431.         function = GXor;
  432.         bc = 0;
  433.     } else {
  434.         goto hard;
  435.     }
  436.     }
  437.     xdev->image.format = XYBitmap;
  438.     X_SET_FUNCTION(xdev, function);
  439.     if (bc != xdev->back_color) {
  440.     XSetBackground(xdev->dpy, xdev->gc, (xdev->back_color = bc));
  441.     }
  442.     if (fc != xdev->fore_color) {
  443.     XSetForeground(xdev->dpy, xdev->gc, (xdev->fore_color = fc));
  444.     }
  445.     if (zero != gx_no_color_index)
  446.     NOTE_COLOR(xdev, zero);
  447.     if (one != gx_no_color_index)
  448.     NOTE_COLOR(xdev, one);
  449.     put_image(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  450.           sourcex, 0, x, y, w, h);
  451.  
  452.     goto out;
  453.  
  454.   hard:            /* Handle the hard 1-color case. */
  455.     if (raster > xdev->cp.raster || h > xdev->cp.height) {
  456.     /* Must allocate a new pixmap and GC. */
  457.     /* Release the old ones first. */
  458.     free_cp(dev);
  459.  
  460.     /* Create the clipping pixmap, depth must be 1. */
  461.     xdev->cp.pixmap =
  462.         XCreatePixmap(xdev->dpy, xdev->win, raster << 3, h, 1);
  463.     if (xdev->cp.pixmap == (Pixmap) 0) {
  464.         lprintf("x_copy_mono: can't allocate pixmap\n");
  465.         return_error(gs_error_VMerror);
  466.     }
  467.     xdev->cp.gc = XCreateGC(xdev->dpy, xdev->cp.pixmap, 0, 0);
  468.     if (xdev->cp.gc == (GC) 0) {
  469.         lprintf("x_copy_mono: can't allocate GC\n");
  470.         return_error(gs_error_VMerror);
  471.     }
  472.     xdev->cp.raster = raster;
  473.     xdev->cp.height = h;
  474.     }
  475.     /* Initialize static mask image params */
  476.     xdev->image.format = XYBitmap;
  477.     X_SET_FUNCTION(xdev, GXcopy);
  478.  
  479.     /* Select polarity based on fg/bg transparency. */
  480.     if (one == gx_no_color_index) {    /* invert */
  481.     XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
  482.     XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
  483.     X_SET_FORE_COLOR(xdev, zero);
  484.     } else {
  485.     XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
  486.     XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
  487.     X_SET_FORE_COLOR(xdev, one);
  488.     }
  489.     put_image(xdev->dpy, xdev->cp.pixmap, xdev->cp.gc,
  490.           &xdev->image, sourcex, 0, 0, 0, w, h);
  491.  
  492.     /* Install as clipmask. */
  493.     XSetClipMask(xdev->dpy, xdev->gc, xdev->cp.pixmap);
  494.     XSetClipOrigin(xdev->dpy, xdev->gc, x, y);
  495.  
  496.     /*
  497.      * Draw a solid rectangle through the raster clip mask.
  498.      * Note fill style is guaranteed to be solid from above.
  499.      */
  500.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  501.  
  502.     /* Tidy up.  Free the pixmap if it's big. */
  503.     XSetClipMask(xdev->dpy, xdev->gc, None);
  504.     if (raster * h > xdev->MaxTempPixmap)
  505.     free_cp(dev);
  506.  
  507.   out:if (xdev->bpixmap != (Pixmap) 0) {
  508.     /* We wrote to the pixmap, so update the display now. */
  509.     x_update_add(xdev, x, y, w, h);
  510.     }
  511.     return 0;
  512. }
  513.  
  514. /* Internal routine to free the GC and pixmap used for copying. */
  515. private void
  516. free_cp(gx_device * dev)
  517. {
  518.     gx_device_X *xdev = (gx_device_X *) dev;
  519.  
  520.     if (xdev->cp.gc != NULL) {
  521.     XFreeGC(xdev->dpy, xdev->cp.gc);
  522.     xdev->cp.gc = NULL;
  523.     }
  524.     if (xdev->cp.pixmap != (Pixmap) 0) {
  525.     XFreePixmap(xdev->dpy, xdev->cp.pixmap);
  526.     xdev->cp.pixmap = (Pixmap) 0;
  527.     }
  528.     xdev->cp.raster = -1;    /* mark as unallocated */
  529. }
  530.  
  531. /* Copy a color bitmap. */
  532. private int
  533. x_copy_image(gx_device_X * xdev, const byte * base, int sourcex, int raster,
  534.          int x, int y, int w, int h)
  535. {
  536.     int depth = xdev->color_info.depth;
  537.  
  538.     X_SET_FILL_STYLE(xdev, FillSolid);
  539.     X_SET_FUNCTION(xdev, GXcopy);
  540.  
  541.     /* Filling with a colored halftone often gives rise to */
  542.     /* copy_color calls for a single pixel.  Check for this now. */
  543.  
  544.     if (h == 1 && w == 1) {
  545.     uint sbit = sourcex * depth;
  546.     const byte *ptr = base + (sbit >> 3);
  547.     x_pixel pixel;
  548.  
  549.     if (depth < 8)
  550.         pixel = (byte) (*ptr << (sbit & 7)) >> (8 - depth);
  551.     else {
  552.         pixel = *ptr++;
  553.         while ((depth -= 8) > 0)
  554.         pixel = (pixel << 8) + *ptr++;
  555.     }
  556.     X_SET_FORE_COLOR(xdev, pixel);
  557.     XDrawPoint(xdev->dpy, xdev->dest, xdev->gc, x, y);
  558.     } else {
  559.     xdev->image.width = sourcex + w;
  560.     xdev->image.height = h;
  561.     xdev->image.format = ZPixmap;
  562.     xdev->image.data = (char *)base;
  563.     xdev->image.depth = depth;
  564.     xdev->image.bytes_per_line = raster;
  565.     xdev->image.bits_per_pixel = depth;
  566.     if (XInitImage(&xdev->image) == 0)
  567.         return_error(gs_error_unknownerror);
  568.     XPutImage(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  569.           sourcex, 0, x, y, w, h);
  570.     xdev->image.depth = xdev->image.bits_per_pixel = 1;
  571.     }
  572.     return 0;
  573. }
  574. private int
  575. x_copy_color(gx_device * dev,
  576.          const byte * base, int sourcex, int raster, gx_bitmap_id id,
  577.          int x, int y, int w, int h)
  578. {
  579.     gx_device_X *xdev = (gx_device_X *) dev;
  580.     int code;
  581.  
  582.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  583.     flush_text(xdev);
  584.     code = x_copy_image(xdev, base, sourcex, raster, x, y, w, h);
  585.     if (xdev->bpixmap != (Pixmap) 0)
  586.     x_update_add(xdev, x, y, w, h);
  587.     if_debug4('F', "[F] copy_color (%d,%d):(%d,%d)\n",
  588.           x, y, w, h);
  589.     return code;
  590. }
  591.  
  592. /* Get the page device.  We reimplement this so that we can make this */
  593. /* device be a page device conditionally. */
  594. private gx_device *
  595. x_get_page_device(gx_device * dev)
  596. {
  597.     return (((gx_device_X *) dev)->IsPageDevice ? dev : (gx_device *) 0);
  598. }
  599.  
  600. /* Tile a rectangle. */
  601. private int
  602. x_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
  603.                int x, int y, int w, int h,
  604.                gx_color_index zero, gx_color_index one,
  605.                int px, int py)
  606. {
  607.     gx_device_X *xdev = (gx_device_X *) dev;
  608.  
  609.     /* Give up if one color is transparent, or if the tile is colored. */
  610.     /* We should implement the latter someday, since X can handle it. */
  611.  
  612.     if (one == gx_no_color_index || zero == gx_no_color_index)
  613.     return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
  614.                            zero, one, px, py);
  615.  
  616.     /* For the moment, give up if the phase or shift is non-zero. */
  617.     if (tiles->shift | px | py)
  618.     return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
  619.                            zero, one, px, py);
  620.  
  621.     fit_fill(dev, x, y, w, h);
  622.     flush_text(xdev);
  623.  
  624.     /* Imaging with a halftone often gives rise to very small */
  625.     /* tile_rectangle calls.  Check for this now. */
  626.  
  627.     if (h <= 2 && w <= 2) {
  628.     int j;
  629.  
  630.     X_SET_FILL_STYLE(xdev, FillSolid);
  631.     X_SET_FUNCTION(xdev, GXcopy);
  632.     for (j = y + h; --j >= y;) {
  633.         const byte *ptr =
  634.         tiles->data + (j % tiles->rep_height) * tiles->raster;
  635.         int i;
  636.  
  637.         for (i = x + w; --i >= x;) {
  638.         uint tx = i % tiles->rep_width;
  639.         byte mask = 0x80 >> (tx & 7);
  640.         x_pixel pixel = (ptr[tx >> 3] & mask ? one : zero);
  641.  
  642.         X_SET_FORE_COLOR(xdev, pixel);
  643.         XDrawPoint(xdev->dpy, xdev->dest, xdev->gc, i, j);
  644.         }
  645.     }
  646.     if (xdev->bpixmap != (Pixmap) 0) {
  647.         x_update_add(xdev, x, y, w, h);
  648.     }
  649.     return 0;
  650.     }
  651.     /*
  652.      * Remember, an X tile is already filled with particular
  653.      * pixel values (i.e., colors).  Therefore if we are changing
  654.      * fore/background color, we must invalidate the tile (using
  655.      * the same technique as in set_tile).  This problem only
  656.      * bites when using grayscale -- you may want to change
  657.      * fg/bg but use the same halftone screen.
  658.      */
  659.     if ((zero != xdev->ht.back_c) || (one != xdev->ht.fore_c))
  660.     xdev->ht.id = ~tiles->id;    /* force reload */
  661.  
  662.     X_SET_BACK_COLOR(xdev, zero);
  663.     X_SET_FORE_COLOR(xdev, one);
  664.     if (!set_tile(dev, tiles)) {    /* Bad news.  Fall back to the default algorithm. */
  665.     return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
  666.                            zero, one, px, py);
  667.     }
  668.     /* Use the tile to fill the rectangle */
  669.     X_SET_FILL_STYLE(xdev, FillTiled);
  670.     X_SET_FUNCTION(xdev, GXcopy);
  671.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  672.     if (xdev->bpixmap != (Pixmap) 0) {
  673.     x_update_add(xdev, x, y, w, h);
  674.     }
  675.     if_debug6('F', "[F] tile (%d,%d):(%d,%d) %ld,%ld\n",
  676.           x, y, w, h, (long)zero, (long)one);
  677.     return 0;
  678. }
  679.  
  680. /* Implement ImageType 2 using CopyArea if possible. */
  681. /* Note that since ImageType 2 images don't have any source data, */
  682. /* this procedure does all the work. */
  683. private int
  684. x_begin_typed_image(gx_device * dev,
  685.             const gs_imager_state * pis, const gs_matrix * pmat,
  686.             const gs_image_common_t * pic, const gs_int_rect * prect,
  687.           const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
  688.             gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
  689. {
  690.     gx_device_X *xdev = (gx_device_X *) dev;
  691.     const gs_image2_t *pim;
  692.     gs_state *pgs;
  693.     gx_device *sdev;
  694.     gs_matrix smat, dmat;
  695.  
  696.     if (pic->type->index != 2)
  697.     goto punt;
  698.     pim = (const gs_image2_t *)pic;
  699.     if (!pim->PixelCopy)
  700.     goto punt;
  701.     pgs = pim->DataSource;
  702.     sdev = gs_currentdevice(pgs);
  703.     if (dev->dname != sdev->dname ||
  704.     memcmp(&dev->color_info, &sdev->color_info,
  705.            sizeof(dev->color_info))
  706.     )
  707.     goto punt;
  708.     flush_text(xdev);
  709.     gs_currentmatrix(pgs, &smat);
  710.     /*
  711.      * Figure 7.2 of the Adobe 3010 Supplement says that we should
  712.      * compute CTM x ImageMatrix here, but I'm almost certain it
  713.      * should be the other way around.  Also see gximage2.c.
  714.      */
  715.     gs_matrix_multiply(&pim->ImageMatrix, &smat, &smat);
  716.     if (pis == 0)
  717.     dmat = *pmat;
  718.     else
  719.     gs_currentmatrix((const gs_state *)pis, &dmat);
  720.     if (!((is_xxyy(&dmat) || is_xyyx(&dmat)) &&
  721. #define eqe(e) smat.e == dmat.e
  722.       eqe(xx) && eqe(xy) && eqe(yx) && eqe(yy))
  723. #undef eqe
  724.     )
  725.     goto punt;
  726.     {
  727.     gs_rect rect, src, dest;
  728.     gs_int_point size;
  729.     int srcx, srcy, destx, desty;
  730.  
  731.     rect.p.x = rect.p.y = 0;
  732.     rect.q.x = pim->Width, rect.q.y = pim->Height;
  733.     gs_bbox_transform(&rect, &dmat, &dest);
  734.     if (pcpath != NULL &&
  735.         !gx_cpath_includes_rectangle(pcpath,
  736.                    float2fixed(dest.p.x), float2fixed(dest.p.y),
  737.                    float2fixed(dest.q.x), float2fixed(dest.q.y))
  738.         )
  739.         goto punt;
  740.     rect.q.x += (rect.p.x = pim->XOrigin);
  741.     rect.q.y += (rect.p.y = pim->YOrigin);
  742.     gs_bbox_transform(&rect, &smat, &src);
  743.     (*pic->type->source_size) (pis, pic, &size);
  744.     X_SET_FILL_STYLE(xdev, FillSolid);
  745.     X_SET_FUNCTION(xdev, GXcopy);
  746.     srcx = (int)(src.p.x + 0.5);
  747.     srcy = (int)(src.p.y + 0.5);
  748.     destx = (int)(dest.p.x + 0.5);
  749.     desty = (int)(dest.p.y + 0.5);
  750.     XCopyArea(xdev->dpy, xdev->bpixmap, xdev->bpixmap, xdev->gc,
  751.           srcx, srcy, size.x, size.y, destx, desty);
  752.     x_update_add(xdev, destx, desty, size.x, size.y);
  753.     }
  754.     return 0;
  755.   punt:return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
  756.                     pdcolor, pcpath, mem, pinfo);
  757. }
  758.  
  759. /* Read bits back from the screen. */
  760. private int
  761. x_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
  762.              gs_get_bits_params_t * params, gs_int_rect ** unread)
  763. {
  764.     gx_device_X *xdev = (gx_device_X *) dev;
  765.     int depth = dev->color_info.depth;
  766.     int x0 = prect->p.x, y0 = prect->p.y, x1 = prect->q.x, y1 = prect->q.y;
  767.     uint width_bytes = ((x1 - x0) * depth + 7) >> 3;
  768.     uint band = xdev->MaxTempImage / width_bytes;
  769.     uint default_raster = bitmap_raster((x1 - x0) * depth);
  770.     gs_get_bits_options_t options = params->options;
  771.     uint raster =
  772.     (options & GB_RASTER_SPECIFIED ? params->raster :
  773.      (params->raster = default_raster));
  774.     long plane_mask = (1L << depth) - 1;
  775.     int y, h;
  776.     XImage *image;
  777.     int code = 0;
  778. #if GET_IMAGE_EXPOSURES
  779.     XWindowAttributes attributes;
  780. #endif /* GET_IMAGE_EXPOSURES */
  781.  
  782.     if (x0 < 0 || y0 < 0 || x1 > dev->width || y1 > dev->height)
  783.     return_error(gs_error_rangecheck);
  784.     /* XGetImage can only handle x_offset = 0. */
  785.     if ((options & GB_OFFSET_SPECIFIED) && params->x_offset == 0)
  786.     options = (options & ~GB_OFFSET_SPECIFIED) | GB_OFFSET_0;
  787.     if (~options &
  788.     (GB_RETURN_COPY | GB_OFFSET_0 | GB_PACKING_CHUNKY |
  789.      GB_COLORS_NATIVE) ||
  790.     !(options & GB_ALIGN_ALL) ||
  791.     !(options & GB_RASTER_ALL)
  792.     )
  793.     return
  794.         gx_default_get_bits_rectangle(dev, prect, params, unread);
  795.     params->options =
  796.     GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY |
  797.     GB_RETURN_COPY | GB_OFFSET_0 |
  798.     (options & GB_ALIGN_ALL) |
  799.     (options & GB_RASTER_SPECIFIED ? GB_RASTER_SPECIFIED :
  800.      GB_RASTER_STANDARD);
  801.     if (x0 >= x1 || y0 >= y1)
  802.     return 0;
  803.     if (x1 <= xdev->update.box.p.x || x0 >= xdev->update.box.q.x ||
  804.     y1 <= xdev->update.box.p.y || y0 >= xdev->update.box.q.y
  805.     ) {
  806.     /*
  807.      * The area being read back doesn't overlap the pending update:
  808.      * just flush text.
  809.      */
  810.     flush_text(xdev);
  811.     } else
  812.     update_do_flush(xdev);
  813.     /*
  814.      * If we want a list of unread rectangles, turn on graphics
  815.      * exposures, and accept exposure events.
  816.      */
  817.     /******
  818.      ****** FOLLOWING IS WRONG.  XGetImage DOES NOT GENERATE
  819.      ****** EXPOSURE EVENTS.
  820.      ******/
  821. #if GET_IMAGE_EXPOSURES
  822.     if (unread) {
  823.     XSetGraphicsExposures(xdev->dpy, xdev->gc, True);
  824.     XGetWindowAttributes(xdev->dpy, xdev->win, &attributes);
  825.     XSelectInput(xdev->dpy, xdev->win,
  826.              attributes.your_event_mask | ExposureMask);
  827.     }
  828. #endif /* GET_IMAGE_EXPOSURES */
  829.     /*
  830.      * The X library doesn't provide any way to specify the desired
  831.      * bit or byte ordering for the result, so we may have to swap the
  832.      * bit or byte order.
  833.      */
  834.     if (band == 0)
  835.     band = 1;
  836.     for (y = y0; y < y1; y += h) {
  837.     int cy;
  838.  
  839.     h = min(band, y1 - y);
  840.     image = XGetImage(xdev->dpy, xdev->dest, x0, y, x1 - x0, h,
  841.               plane_mask, ZPixmap);
  842.     for (cy = y; cy < y + h; ++cy) {
  843.         const byte *source =
  844.         (const byte *)image->data + (cy - y) * image->bytes_per_line;
  845.         byte *dest = params->data[0] + (cy - y0) * raster;
  846.  
  847.         /*
  848.          * XGetImage can return an image with any bit order, byte order,
  849.          * unit size (for bitmaps), and bits_per_pixel it wants: it's up
  850.          * to us to convert the results.  (It's a major botch in the X
  851.          * design that even though the server has to have the ability to
  852.          * convert images from any format to any format, there's no way
  853.          * to specify a requested format for XGetImage.)
  854.          */
  855.         if (image->bits_per_pixel == image->depth &&
  856.         (image->depth > 1 || image->bitmap_bit_order == MSBFirst) &&
  857.         (image->byte_order == MSBFirst || image->depth <= 8)
  858.         ) {
  859.         /*
  860.          * The server has been nice enough to return an image in the
  861.          * format we use.  
  862.          */
  863.         memcpy(dest, source, width_bytes);
  864.         } else {
  865.         /*
  866.          * We need to swap byte order and/or bit order.  What a
  867.          * totally unnecessary nuisance!  For the moment, the only
  868.          * cases we deal with are 16- and 24-bit images with padding
  869.          * and/or byte swapping.
  870.          */
  871.         if (image->depth == 24) {
  872.             int cx;
  873.             const byte *p = source;
  874.             byte *q = dest;
  875.             int step = image->bits_per_pixel >> 3;
  876.  
  877.             if (image->byte_order == MSBFirst) {
  878.             p += step - 3;
  879.             for (cx = x0; cx < x1; p += step, q += 3, ++cx)
  880.                 q[0] = p[0], q[1] = p[1], q[2] = p[2];
  881.             } else {
  882.             for (cx = x0; cx < x1; p += step, q += 3, ++cx)
  883.                 q[0] = p[2], q[1] = p[1], q[2] = p[0];
  884.             }
  885.         } else if (image->depth == 16) {
  886.             int cx;
  887.             const byte *p = source;
  888.             byte *q = dest;
  889.             int step = image->bits_per_pixel >> 3;
  890.  
  891.             if (image->byte_order == MSBFirst) {
  892.             p += step - 2;
  893.             for (cx = x0; cx < x1; p += step, q += 2, ++cx)
  894.                 q[0] = p[0], q[1] = p[1];
  895.             } else {
  896.             for (cx = x0; cx < x1; p += step, q += 2, ++cx)
  897.                 q[0] = p[1], q[1] = p[0];
  898.             }
  899.         } else
  900.             code = gs_note_error(gs_error_rangecheck);
  901.         }
  902.     }
  903.     XDestroyImage(image);
  904.     }
  905.     if (unread) {
  906. #if GET_IMAGE_EXPOSURES
  907.     XEvent event;
  908. #endif /* GET_IMAGE_EXPOSURES */
  909.  
  910.     *unread = 0;
  911. #if GET_IMAGE_EXPOSURES
  912.     /* Read any exposure events. */
  913.     XWindowEvent(xdev->dpy, xdev->win, ExposureMask, &event);
  914.     if (event.type == GraphicsExpose) {
  915.         gs_int_rect *rects = (gs_int_rect *)
  916.         gs_alloc_bytes(dev->memory, sizeof(gs_int_rect),
  917.                    "x_get_bits_rectangle");
  918.         int num_rects = 0;
  919.  
  920.         for (;;) {
  921.         if (rects == 0) {
  922.             code = gs_note_error(gs_error_VMerror);
  923.             break;
  924.         }
  925. #define xevent (*(XGraphicsExposeEvent *)&event)
  926.         rects[num_rects].q.x = xevent.width +
  927.             (rects[num_rects].p.x = xevent.x);
  928.         rects[num_rects].q.y = xevent.height +
  929.             (rects[num_rects].p.y = xevent.y);
  930.         ++num_rects;
  931.         if (!xevent.count)
  932.             break;
  933. #undef xevent
  934.         rects = gs_resize_object(dev->memory, rects,
  935.                      (num_rects + 1) * sizeof(gs_int_rect),
  936.                      "x_get_bits_rectangle");
  937.         }
  938.         if (code >= 0) {
  939.         *unread = rects;
  940.         code = num_rects;
  941.         }
  942.     }
  943.     /* Restore the window state. */
  944.     XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
  945.     XSelectInput(xdev->dpy, xdev->win, attributes.your_event_mask);
  946. #endif /* GET_IMAGE_EXPOSURES */
  947.     }
  948.     return code;
  949. }
  950.  
  951. /* Set up with a specified tile. */
  952. /* Return false if we can't do it for some reason. */
  953. private int
  954. set_tile(gx_device * dev, const gx_strip_bitmap * tile)
  955. {
  956.     gx_device_X *xdev = (gx_device_X *) dev;
  957.  
  958. #ifdef DEBUG
  959.     if (gs_debug['T'])
  960.     return 0;
  961. #endif
  962.     if (tile->id == xdev->ht.id && tile->id != gx_no_bitmap_id)
  963.     return xdev->useXSetTile;
  964.     /* Set up the tile Pixmap */
  965.     if (tile->size.x != xdev->ht.width ||
  966.     tile->size.y != xdev->ht.height ||
  967.     xdev->ht.pixmap == (Pixmap) 0) {
  968.     if (xdev->ht.pixmap != (Pixmap) 0)
  969.         XFreePixmap(xdev->dpy, xdev->ht.pixmap);
  970.     xdev->ht.pixmap = XCreatePixmap(xdev->dpy, xdev->win,
  971.                     tile->size.x, tile->size.y,
  972.                     xdev->vinfo->depth);
  973.     if (xdev->ht.pixmap == (Pixmap) 0)
  974.         return 0;
  975.     xdev->ht.width = tile->size.x, xdev->ht.height = tile->size.y;
  976.     xdev->ht.raster = tile->raster;
  977.     }
  978.     xdev->ht.fore_c = xdev->fore_color;
  979.     xdev->ht.back_c = xdev->back_color;
  980.     /* Copy the tile into the Pixmap */
  981.     xdev->image.data = (char *)tile->data;
  982.     xdev->image.width = tile->size.x;
  983.     xdev->image.height = tile->size.y;
  984.     xdev->image.bytes_per_line = tile->raster;
  985.     xdev->image.format = XYBitmap;
  986.     X_SET_FILL_STYLE(xdev, FillSolid);
  987. #ifdef DEBUG
  988.     if (gs_debug['H']) {
  989.     int i;
  990.  
  991.     dlprintf4("[H] 0x%lx: width=%d height=%d raster=%d\n",
  992.           (ulong) tile->data, tile->size.x, tile->size.y, tile->raster);
  993.     dlputs("");
  994.     for (i = 0; i < tile->raster * tile->size.y; i++)
  995.         dprintf1(" %02x", tile->data[i]);
  996.     dputc('\n');
  997.     }
  998. #endif
  999.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.no_pixmap);    /* *** X bug *** */
  1000.     X_SET_FUNCTION(xdev, GXcopy);
  1001.     put_image(xdev->dpy, xdev->ht.pixmap, xdev->gc, &xdev->image,
  1002.           0, 0, 0, 0, tile->size.x, tile->size.y);
  1003.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.pixmap);
  1004.     xdev->ht.id = tile->id;
  1005.     return xdev->useXSetTile;
  1006. }
  1007.  
  1008. /* ------ Screen update procedures ------ */
  1009.  
  1010. /* Initialize the update machinery. */
  1011. private void
  1012. update_init(gx_device_X *xdev)
  1013. {
  1014.     xdev->update.box.p.x = xdev->update.box.p.y = max_int_in_fixed;
  1015.     xdev->update.box.q.x = xdev->update.box.q.y = min_int_in_fixed;
  1016.     xdev->update.area = xdev->update.total = xdev->update.count = 0;
  1017. }
  1018.  
  1019. /* Flush updates to the screen if needed. */
  1020. private void
  1021. update_do_flush(gx_device_X * xdev)
  1022. {
  1023.     flush_text(xdev);
  1024.     if (xdev->update.count != 0) {
  1025.     int x = xdev->update.box.p.x, y = xdev->update.box.p.y;
  1026.     int w = xdev->update.box.q.x - x, h = xdev->update.box.q.y - y;
  1027.  
  1028.     fit_fill_xywh(xdev, x, y, w, h);
  1029.     if (w > 0 && h > 0) {
  1030.         if (xdev->is_buffered) {
  1031.         /* Copy from memory image to X server. */
  1032.         const gx_device_memory *mdev =
  1033.             (const gx_device_memory *)xdev->target;
  1034.  
  1035.         /*
  1036.          * The bbox device may have set the target to NULL
  1037.          * temporarily.  If this is the case, defer the screen
  1038.          * update.
  1039.          */
  1040.         if (mdev == NULL)
  1041.             return;    /* don't reset */
  1042.         x_copy_image(xdev, mdev->line_ptrs[y], x, mdev->raster,
  1043.                  x, y, w, h);
  1044.         }
  1045.         if (xdev->bpixmap) {
  1046.         /* Copy from X backing pixmap to screen. */
  1047.  
  1048.         X_SET_FUNCTION(xdev, GXcopy);
  1049.         XCopyArea(xdev->dpy, xdev->bpixmap, xdev->win, xdev->gc,
  1050.               x, y, w, h, x, y);
  1051.         }
  1052.     }
  1053.     update_init(xdev);
  1054.     }
  1055. }
  1056.  
  1057. /* Add a region to be updated, after writing to that region. */
  1058. void
  1059. x_update_add(gx_device_X * xdev, int xo, int yo, int w, int h)
  1060. {
  1061.     int xe = xo + w, ye = yo + h;
  1062.     long added = (long)w * h;
  1063.     long old_area = xdev->update.area;
  1064.     gs_int_rect u;
  1065.     int nw, nh;
  1066.     long new_up_area;
  1067.  
  1068.     u.p.x = min(xo, xdev->update.box.p.x);
  1069.     u.p.y = min(yo, xdev->update.box.p.y);
  1070.     u.q.x = max(xe, xdev->update.box.q.x);
  1071.     u.q.y = max(ye, xdev->update.box.q.y);
  1072.     nw = u.q.x - u.p.x;
  1073.     nh = u.q.y - u.p.y;
  1074.     new_up_area = (long)nw * nh;
  1075.     xdev->update.count++;
  1076.     xdev->update.area = new_up_area;
  1077.     xdev->update.total += added;
  1078.     if (!xdev->AlwaysUpdate &&
  1079.     xdev->update.count < xdev->MaxBufferedCount &&
  1080.     xdev->update.area < xdev->MaxBufferedArea &&
  1081.     xdev->update.total < xdev->MaxBufferedTotal
  1082.     ) {
  1083.     /*
  1084.      * Test whether adding this rectangle would result in too much being
  1085.      * copied unnecessarily.  The fraction of new_up_area used in the
  1086.      * following test is not particularly critical; using a denominator
  1087.      * that is a power of 2 eliminates a divide.
  1088.      */
  1089.     if (nw + nh >= 70 && (nw | nh) >= 16 &&
  1090.         old_area + added < new_up_area - (new_up_area >> 2)
  1091.         )
  1092.         DO_NOTHING;
  1093.     else {
  1094.         xdev->update.box = u;
  1095.         return;
  1096.     }
  1097.     }
  1098.     update_do_flush(xdev);
  1099.     xdev->update.box.p.x = xo, xdev->update.box.p.y = yo;
  1100.     xdev->update.box.q.x = xe, xdev->update.box.q.y = ye;
  1101.     xdev->update.count = 1;
  1102.     xdev->update.area = xdev->update.total = added;
  1103. }
  1104.  
  1105. /* Flush buffered text to the screen. */
  1106. private void
  1107. do_flush_text(gx_device_X * xdev)
  1108. {
  1109.     if (!IN_TEXT(xdev))
  1110.     return;
  1111.     DRAW_TEXT(xdev);
  1112.     xdev->text.item_count = xdev->text.char_count = 0;
  1113. }
  1114.  
  1115. /* Bounding box device procedures (only used when buffering) */
  1116. private bool
  1117. x_bbox_init_box(void *pdata)
  1118. {
  1119.     gx_device_X *const xdev = pdata;
  1120.  
  1121.     update_init(xdev);
  1122.     return true;
  1123. }
  1124. private void
  1125. x_bbox_get_box(const void *pdata, gs_fixed_rect *pbox)
  1126. {
  1127.     const gx_device_X *const xdev = pdata;
  1128.  
  1129.     pbox->p.x = int2fixed(xdev->update.box.p.x);
  1130.     pbox->p.y = int2fixed(xdev->update.box.p.y);
  1131.     pbox->q.x = int2fixed(xdev->update.box.q.x);
  1132.     pbox->q.y = int2fixed(xdev->update.box.q.y);
  1133. }
  1134. private void
  1135. x_bbox_add_rect(void *pdata, fixed x0, fixed y0, fixed x1, fixed y1)
  1136. {
  1137.     gx_device_X *const xdev = pdata;
  1138.     int x = fixed2int(x0), y = fixed2int(y0);
  1139.  
  1140.     x_update_add(xdev, x, y, fixed2int_ceiling(x1) - x,
  1141.          fixed2int_ceiling(y1) - y);
  1142. }
  1143. private bool
  1144. x_bbox_in_rect(const void *pdata, const gs_fixed_rect *pbox)
  1145. {
  1146.     gs_fixed_rect box;
  1147.  
  1148.     x_bbox_get_box(pdata, &box);
  1149.     return rect_within(*pbox, box);
  1150. }
  1151. const gx_device_bbox_procs_t gdev_x_box_procs = {
  1152.     x_bbox_init_box, x_bbox_get_box, x_bbox_add_rect, x_bbox_in_rect
  1153. };
  1154.  
  1155. /* ------ Internal procedures ------ */
  1156.  
  1157. /*
  1158.  * Substitute for XPutImage using XFillRectangle.  This is a hack to get
  1159.  * around an apparent bug in some X servers.  It only works with the
  1160.  * specific parameters (bit/byte order, padding) used above.
  1161.  */
  1162. private int
  1163. alt_put_image(gx_device *dev, Display *dpy, Drawable win, GC gc, XImage *pi,
  1164.           int sx, int sy, int dx, int dy, unsigned w, unsigned h)
  1165. {
  1166.     int raster = pi->bytes_per_line;
  1167.     byte *data = (byte *) pi->data + sy * raster + (sx >> 3);
  1168.     int init_mask = 0x80 >> (sx & 7);
  1169.     int invert = 0;
  1170.     int yi;
  1171. #define NUM_RECTS 40
  1172.     XRectangle rects[NUM_RECTS];
  1173.     XRectangle *rp = rects;
  1174.     XGCValues gcv;
  1175.  
  1176. #ifdef DEBUG
  1177.     if (pi->format != XYBitmap || pi->byte_order != MSBFirst ||
  1178.     pi->bitmap_bit_order != MSBFirst || pi->depth != 1
  1179.     ) {
  1180.     lprintf("alt_put_image: unimplemented parameter values!\n");
  1181.     return_error(gs_error_rangecheck);
  1182.     }
  1183. #endif
  1184.  
  1185.     XGetGCValues(dpy, gc, (GCFunction | GCForeground | GCBackground), &gcv);
  1186.  
  1187.     if (gcv.function == GXcopy) {
  1188.     XSetForeground(dpy, gc, gcv.background);
  1189.     XFillRectangle(dpy, win, gc, dx, dy, w, h);
  1190.     XSetForeground(dpy, gc, gcv.foreground);
  1191.     } else if (gcv.function == GXand) {
  1192.     /* The only cases used above are fc = ~0 or bc = ~0. */
  1193. #ifdef DEBUG
  1194.     if (gcv.foreground != ~(x_pixel)0 && gcv.background != ~(x_pixel)0) {
  1195.         lprintf("alt_put_image: unimplemented GXand case!\n");
  1196.         return_error(gs_error_rangecheck);
  1197.     }
  1198. #endif
  1199.     if (gcv.background != ~(x_pixel) 0) {
  1200.         XSetForeground(dpy, gc, gcv.background);
  1201.         invert = 0xff;
  1202.     }
  1203.     } else if (gcv.function == GXor) {
  1204.     /* The only cases used above are fc = 0 or bc = 0. */
  1205. #ifdef DEBUG
  1206.     if (gcv.foreground != 0 && gcv.background != 0) {
  1207.         lprintf("alt_put_image: unimplemented GXor case!\n");
  1208.         return_error(gs_error_rangecheck);
  1209.     }
  1210. #endif
  1211.     if (gcv.background != 0) {
  1212.         XSetForeground(dpy, gc, gcv.background);
  1213.         invert = 0xff;
  1214.     }
  1215.     } else {
  1216.     lprintf("alt_put_image: unimplemented function.\n");
  1217.     return_error(gs_error_rangecheck);
  1218.     }
  1219.  
  1220.     for (yi = 0; yi < h; yi++, data += raster) {
  1221.     int mask = init_mask;
  1222.     byte *dp = data;
  1223.     int xi = 0;
  1224.  
  1225.     while (xi < w) {
  1226.         if ((*dp ^ invert) & mask) {
  1227.         int xleft = xi;
  1228.  
  1229.         if (rp == &rects[NUM_RECTS]) {
  1230.             XFillRectangles(dpy, win, gc, rects, NUM_RECTS);
  1231.             rp = rects;
  1232.         }
  1233.         /* Scan over a run of 1-bits */
  1234.         rp->x = dx + xi, rp->y = dy + yi;
  1235.         do {
  1236.             if (!(mask >>= 1))
  1237.             mask = 0x80, dp++;
  1238.             xi++;
  1239.         } while (xi < w && ((*dp ^ invert) & mask));
  1240.         rp->width = xi - xleft, rp->height = 1;
  1241.         rp++;
  1242.         } else {
  1243.         if (!(mask >>= 1))
  1244.             mask = 0x80, dp++;
  1245.         xi++;
  1246.         }
  1247.     }
  1248.     }
  1249.     XFillRectangles(dpy, win, gc, rects, rp - rects);
  1250.     if (invert)
  1251.     XSetForeground(dpy, gc, gcv.foreground);
  1252.     return 0;
  1253. #undef NUM_RECTS
  1254. }
  1255.